import java.io.*;
import java.net.*;
import java.security.KeyStore;

import javax.net.ServerSocketFactory;
import javax.net.ssl.*;

public class ChatServer{



	//static  Socket clientSocket = null;
	//static  ServerSocket serverSocket = null;


	//static SSLServerSocketFactory sslserversocketfactory =                null;
	//static SSLServerSocket sslserversocket = null;
	static SSLSocket sslsocket = null;
	static SSLServerSocket ss=null;


	static  clientThread t[] = new clientThread[20];           //XXXXXXX-- 20 client threads at a time

	public static void main(String args[]) {



		int port_number=2222;

		if (args.length < 1)
		{
			System.out.println("Now using port number="+port_number);
		} else {
			port_number=Integer.valueOf(args[0]).intValue();
		}


		try{
			ServerSocketFactory ssf = getServerSocketFactory("SSL");
			ss = (SSLServerSocket)ssf.createServerSocket(port_number);
			ss.setNeedClientAuth(true);

			//sslserversocketfactory =                (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
			//sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port_number);
			sslsocket = null;
		}
		catch(Exception e)
		{

		}


		/*try {
			//serverSocket = new ServerSocket(port_number);
		}
		catch (IOException e)
		{System.out.println(e);}*/


		while(true){
			try {
				sslsocket = (SSLSocket) ss.accept();
				//clientSocket = serverSocket.accept();
				for(int i=0; i<20; i++){
					if(t[i]==null)
					{
						(t[i] = new clientThread(sslsocket,t)).start();
						break;
					}
				}
			}
			catch (IOException e) {
				System.out.println(e);}
		}
	}


	private static ServerSocketFactory getServerSocketFactory(String type) {
		if (type.equals("SSL")) {
			System.setProperty("javax.net.ssl.trustStore", "new_client.jks");
			System.setProperty("javax.net.ssl.trustStorePassword", "clientstorepass");
			SSLServerSocketFactory ssf = null;
			try {
				// set up key manager to do server authentication
				SSLContext ctx;
				KeyManagerFactory kmf;
				KeyStore ks;
				char[] passphrase = "clientstorepass".toCharArray();

				ctx = SSLContext.getInstance("SSL");
				kmf = KeyManagerFactory.getInstance("SunX509");
				ks = KeyStore.getInstance("JKS");

				ks.load(new FileInputStream("new_client.jks"), passphrase);
				kmf.init(ks, "clientkeypass".toCharArray());
				ctx.init(kmf.getKeyManagers(), null, null);

				ssf = ctx.getServerSocketFactory();
				return ssf;
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			return ServerSocketFactory.getDefault();
		}
		return null;
	}
} 



class clientThread extends Thread {

	DataInputStream is = null;
	PrintStream os = null;
	SSLSocket clientSocket = null;       
	clientThread t[]; 

	public clientThread(SSLSocket clientSocket, clientThread[] t){
		this.clientSocket=clientSocket;
		this.t=t;
	}

	@SuppressWarnings("deprecation")
	public void run()
	{
		String uName=null;
		String cmd;
		//String cert;
		String filename=null,userdir=null;
		FileInputStream fis=null;
		FileOutputStream fos=null;
		boolean find=false;
		try{
			is = new DataInputStream(clientSocket.getInputStream());
			os = new PrintStream(clientSocket.getOutputStream());
			os.println("Send the commands Please.");
			//cert = is.readLine();//get the certificate here

			//if not valid then terminate close here
			//Start up SSL
			//XXXXX-- uName determine username from the certificate
			uName="Client1";
			try
			{
				FileReader fro = new FileReader( "serverDB.txt" );
				BufferedReader bro = new BufferedReader( fro );

				String stringFromFile = bro.readLine( );

				while( stringFromFile != null || !find) // end of the file
				{
					System.out.println(stringFromFile);
					find=findMatch(stringFromFile,bro,uName);
					if(find)
					{
						System.out.println("got something");
						userdir= getMatch(stringFromFile,bro,uName);
						break;
					}
					stringFromFile = bro.readLine( );  // read next line
				}

				bro.close( );
			}

			catch( FileNotFoundException filenotfoundexxption )
			{
				System.out.println( "Server file does not exist" );
			}

			catch( IOException ioexception )
			{
				ioexception.printStackTrace( );
			}

			//determine per user directory
			//userdir --add to the filename the absolute per user directory
			//start SSL


			while(true)
			{
				filename=userdir;
				System.out.println("user dir is "+ filename);
				cmd = is.readLine();
				System.out.println("cmd sent is "+ cmd);
				if(cmd.equalsIgnoreCase("/quit"))
				{
					System.out.println("client want to go  ");
					break;
				}
				String cmdargs[]=cmd.split(" ");
				if(cmdargs.length!=2)
				{

					os.println("Wrong command");
					continue;
					//close
				}
				else{
					//System.out.println("cmd in r w  "+ cmd);

					if(cmdargs[0].equals("r"))
					{
						System.out.println("cmd in r   "+ cmdargs[0] +" "+cmdargs[1]);
						filename+=cmdargs[1];
						fis=new FileInputStream(filename);
						if(fis!=null)
						{

							os.println("ok");


							try{
								System.out.println("calling send");;
								//sendBytes(fis,os);
								sendFile(filename);

							}
							catch(Exception e){};
						}
					}
					else if(cmdargs[0].equals("w"))
					{
						filename+=cmdargs[1];
						fos=new FileOutputStream(filename);
						if(fos!=null){
							os.println("ok");
							//read the data and write to the filename


						}
					}
				}
				//get the "r" or "w" and the file name
				//If r then send the status message and then file data to client 
				//If w  send status message  and create a file at the server in the user directory and wait for data

			}

			is.close();
			os.close();
			clientSocket.close();
		}
		catch(IOException e){};
	}

	private static void sendBytes(FileInputStream fis, OutputStream os) throws Exception
	{
		// Construct a 1K buffer to hold bytes on r way to the socket.
		System.out.println("frm sendbytes");

		byte[] buffer = new byte[1024];
		//String s="ByeBye";
		//byte b[]=s.getBytes(s);
		int bytes = 0;

		// Copy requested file into the socket's output stream.
		while(true) {
			bytes = fis.read(buffer) ;
			if(bytes!=-1)
			{
				os.write(buffer, 0, bytes);
			}

			
		}
	}
	
	
	public void sendFile(String file){
		try{
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			BufferedOutputStream bos = new BufferedOutputStream(clientSocket.getOutputStream( ));
		byte byteArray[] = new byte[8192];
		int in;
		while ((in = bis.read(byteArray)) != -1){
		bos.write(byteArray,0,in);
		}
		//bis.close();
		//bos.close();
		}
		catch(IOException e){
		e.printStackTrace();
		}
		}


	private boolean createDir(String strDirectoy){
		try{
			boolean success = (new File(strDirectoy)).mkdir();
			return success;

		}catch (Exception e){//Catch exception if any
			//System.err.println("Error: " + e.getMessage());
			return false;
		}
	}

	private boolean createManyDir(String strManyDirectories){
		try{

			boolean  success = (new File(strManyDirectories)).mkdirs();
			return success;

		}
		catch (Exception e){//Catch exception if any
			//System.err.println("Error: " + e.getMessage());
			return false;
		}
	}


	private boolean findMatch(String line,BufferedReader bro,String uName){
		String arr[]=line.split(";");
		arr[0]=arr[0].trim();
		if(arr[0].equalsIgnoreCase(uName))
		{
			return true;
		}
		else{
			return false;
		}
	}

	private String getMatch(String line,BufferedReader bro,String uName){
		String arr[]=line.split(";");
		arr[0]=arr[0].trim();
		arr[1]=arr[1].trim();
		if(arr[0].equalsIgnoreCase(uName))
		{
			return arr[1];
		}
		else{
			return null;
		}
	}


}

